iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Software Development

從像素到 Computer Vision:30 天理解數位影像處理系列 第 13

Day 13 | Sobel Operator:如何找出圖片的亮度變化?

  • 分享至 

  • xImage
  •  

上一篇介紹了 Image Gradient。

我們知道,電腦並不知道圖片裡有沒有狗、有沒有樹,也不知道哪裡是物體。

它真正尋找的是亮度變化最大的地方。

不過,知道這件事之後,又有另一個問題。

如果要判斷某個 Pixel 的亮度變化,電腦到底要怎麼算?

總不能把整張圖片全部拿來比較吧?

其實,只需要觀察附近幾個 Pixel,就能估計亮度的變化。

而最經典的方法之一,就是 Sobel Operator

Sobel 在做什麼?

Sobel 的想法其實很直接。

如果想知道亮度是不是往左右改變,那就比較左邊和右邊。

如果想知道亮度是不是往上下改變,那就比較上面和下面。

也就是說,Sobel 其實就是在估計亮度在不同方向上的變化。

為什麼要分成 X 和 Y?

假設圖片有一條垂直的黑白分界。

0   0   0   255   255
0   0   0   255   255
0   0   0   255   255

左右方向的亮度變化非常大。

上下方向則幾乎沒有變化。

因此:

  • X 方向 Gradient 很大
  • Y 方向 Gradient 很小

如果今天換成水平邊界。

0   0   0   0   0

255 255 255 255 255

結果就會反過來。

因此,Sobel 會分別計算:

  • X 方向 Gradient
  • Y 方向 Gradient

最後再把兩個方向的資訊結合起來。

Sobel Kernel 長什麼樣子?

上一篇提到,Gradient 也是利用 Convolution 完成的。

因此 Sobel 一樣需要 Kernel。

計算 X 方向時,使用:

-1  0  1
-2  0  2
-1  0  1

計算 Y 方向時,使用:

-1 -2 -1
 0  0  0
 1  2  1

可以發現,X 方向的 Kernel,左邊都是負數,右邊都是正數。

它其實就是在比較:

左邊和右邊哪一側比較亮。

而 Y 方向也是相同的概念,只是改成比較上方和下方。

為什麼中間那一列(或那一欄)權重比較大?

如果仔細看:

-1  0  1
-2  0  2
-1  0  1

會發現,中間那一列不是 ±1,而是 ±2。

這代表什麼?

代表 Sobel 認為,距離中心最近的 Pixel,比上下兩側更值得參考。

因此給它更大的權重。

這也是 Sobel 和最簡單的差分運算不同的地方。

它除了估計亮度變化之外,也稍微考慮了周圍 Pixel,因此對雜訊比較不敏感。

實作:使用 Sobel

OpenCV 已經提供了 Sobel Operator。

import cv2
import matplotlib.pyplot as plt

img = cv2.imread("dog.jpeg", cv2.IMREAD_GRAYSCALE)

grad_x = cv2.Sobel(img, cv2.CV_64F, 1, 0)
grad_y = cv2.Sobel(img, cv2.CV_64F, 0, 1)

其中:

  • dx=1, dy=0 表示計算 X 方向 Gradient。
  • dx=0, dy=1 表示計算 Y 方向 Gradient。

把結果一起顯示。

plt.figure(figsize=(12,4))

plt.subplot(1,3,1)
plt.imshow(img, cmap="gray")
plt.title("Original")
plt.axis("off")

plt.subplot(1,3,2)
plt.imshow(cv2.convertScaleAbs(grad_x), cmap="gray")
plt.title("Gradient X")
plt.axis("off")

plt.subplot(1,3,3)
plt.imshow(cv2.convertScaleAbs(grad_y), cmap="gray")
plt.title("Gradient Y")
plt.axis("off")

plt.tight_layout()
plt.show()

結果:

https://ithelp.ithome.com.tw/upload/images/20260830/20181780XBfU4Hdaol.png

可以觀察看看,X 和 Y 的結果並不一樣。

有些邊緣只會在其中一張圖變得很明顯。

因為不同方向的亮度變化,本來就不同。

如果只有 X 或只有 Y 夠嗎?

答案是:通常不夠。

因為一張圖片裡物體的邊界不可能全部都是水平或垂直。

除非被壓扁

https://ithelp.ithome.com.tw/upload/images/20260830/20181780ANdy9Cuzpl.png

因此實際應用時,通常會把兩個方向一起考慮。

OpenCV 可以利用 cv2.magnitude() 將兩個方向的 Gradient 合成。

magnitude = cv2.magnitude(grad_x, grad_y)

得到的結果,就是每個 Pixel 的 Gradient 大小。

Gradient 越大,代表亮度變化越劇烈,也越有可能是邊緣。

Sobel 有什麼限制?

Sobel 雖然能找到亮度變化。

但它並不知道哪些變化是真正的物體邊界,哪些又只是光線、陰影或雜訊造成的。

因此,Sobel 的結果通常還不是最後的邊緣圖。

它更像是一張: 哪裡可能有邊緣的提示圖。

後續還需要其他方法進一步處理。

今天總結

今天介紹了 Sobel Operator。

它利用兩組不同方向的 Kernel,估計圖片在 X 和 Y 方向上的亮度變化。

Sobel 真正計算的是 Gradient,而不是直接辨識物體。

不過,因為物體邊界通常伴隨著劇烈的亮度變化,因此 Sobel 常被用來作為邊緣偵測的重要步驟。

明天,我們會介紹另一個和 Sobel 很相似的方法:

Prewitt Operator

看看它和 Sobel 到底差在哪裡,又為什麼現在大多數情況下更常看到 Sobel。


上一篇
Day 12 | Image Gradient:電腦怎麼知道哪裡是邊緣?
下一篇
Day 14 | Prewitt Operator:它和 Sobel 到底差在哪裡?
系列文
從像素到 Computer Vision:30 天理解數位影像處理25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言